package com.znf4.aop.currentlimit;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import com.znf4.cache.redis.RedisUtils;
import com.znf4.utils.StringUtil;

import redis.clients.jedis.Jedis;

/**
 * 限流切面
 * 
 * @author agui
 *
 */
@Aspect
@Component
public class CurrentLimitAspect {
	private static final Logger logger = LoggerFactory.getLogger(CurrentLimitAspect.class);


	/**
	 * 切点 注解拦截
	 */
	@Pointcut(value = "@annotation(com.znf4.aop.currentlimit.CurrentLimit)")
	public void aspect() {
	}

	/**
	 * 环绕通知
	 * 
	 * @param joinPoint
	 *            切点
	 * @throws InterruptedException
	 */
	@SuppressWarnings("null")
	@Around("aspect()")
	public void around(ProceedingJoinPoint joinPoint) throws InterruptedException {
		try {
			MethodSignature signature = (MethodSignature) joinPoint.getSignature();
			Method method = signature.getMethod();
			CurrentLimit currentLimit = method.getAnnotation(CurrentLimit.class);
			int limit = currentLimit.limit(); // 线程个数
			int timeout = currentLimit.timeout(); // 超时时间
			boolean isController = currentLimit.isController() ;  // 是否加载controller上
			
            Jedis jedis = RedisUtils.getJedisSentinelPool().getResource() ;
			String result = RedisCurrentLimit.acquireTokenFromBucket(jedis,
					limit, timeout);
			jedis.close(); 
			if (StringUtil.isEmpty(result)) {
				logger.info("------线程被限流-----");
				HttpServletResponse response = null ;
				if(isController){
					installHttpServletResponse(joinPoint , response ) ;
					response.getWriter().write("close");
				}
				return;
			}
			joinPoint.proceed();
		} catch (Throwable e) {
			e.printStackTrace();
		}

	}

	/**
	 * 实例化 HttpServletResponse
	 * @param joinPoint
	 * @param response
	 */
	private void installHttpServletResponse(ProceedingJoinPoint joinPoint, HttpServletResponse response) {
		Object[] obj =  joinPoint.getArgs() ;
    	for(int i =0 ; i < obj.length ; i++){
    		if(obj[i] instanceof HttpServletResponse ){
    			 response = (HttpServletResponse) obj[i] ;
    			 break ;
    		}
    	}
		
	}

	/**
	 * 异常通知 记录操作报错日志
	 * 
	 * @param joinPoint
	 * @param e
	 */
	@AfterThrowing(pointcut = "aspect()", throwing = "e")
	public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {

	}

}
